package model

/*******************************************************************************
Copyright:cloud
Author:cloudapex@126.com
Version:1.0
Date:2020-07-07
Description: 用户模型
*******************************************************************************/

import (
	"errors"
	"fmt"

	"gitee.com/cloudapex/ulern/util"
	"xorm.io/xorm"
)

// => 用户表
type User struct {
	Id     int64  `json:"id" xorm:"pk"`
	Name   string `json:"name" xorm:"varchar(64) notnull"`   // 名称
	Sex    int32  `json:"sex" xorm:"notnull default 1"`      // 性别(1:男; 2:女)
	Phone  int64  `json:"phone" xorm:"notnull"`              // 手机
	Email  string `json:"email" xorm:"varchar(128) notnull"` // 邮箱
	State  int    `json:"state" xorm:"notnull default 1"`    // 状态(1:正常;2:失效)
	Remark string `json:"remark" xorm:"varchar(128)"`        // 备注

	CreatedAt util.TJsTime `json:"at" xorm:"index created"`
	UpdatedAt util.TJsTime `json:"-" xorm:"updated"`
	DeletedAt util.TJsTime `json:"-" xorm:"deleted"`

	Sorte SortFinder `json:"-" xorm:"-"`
	Pager PageFinder `json:"-" xorm:"-"`
}

// => 用户与角色关联表
type UserRole struct {
	Id        int64
	UserId    int64        `xorm:"notnull index"` // 用户Id
	RoleId    int64        `xorm:"notnull index"` // 角色Id
	CreatedAt util.TJsTime `xorm:"created"`
}

// => 用户与用户组关联表
type UserGroup struct {
	Id        int64
	UserId    int64        `xorm:"notnull index"` // 用户Id
	GroupId   int64        `xorm:"notnull index"` // 用户组Id
	CreatedAt util.TJsTime `xorm:"created"`
}

// ----- User
func (this *User) Load() (bool, error) {
	return MDB(EMDB_Permt).Get(this)
}
func (this *User) Create() (int64, error) {
	return MDB(EMDB_Permt).Insert(this)
}
func (this *User) Update(id int64, columns ...string) (int64, error) {
	return MDB(EMDB_Permt).ID(id).MustCols(columns...).Update(this)
}
func (this *User) Delete(id int64) (int64, error) {
	return MDB(EMDB_Permt).ID(id).Delete(&User{})
}
func (this *User) Orders() map[string]string {
	return map[string]string{"id": "id", "at": "created_at"}
}
func (this *User) condis(q *xorm.Session, tbl string) *xorm.Session {
	util.Cast(tbl != "", func() { tbl += "." }, nil)

	if this.Id != 0 {
		q = q.Where(fmt.Sprintf("%sid = ?", tbl), this.Id)
	}
	if this.Name != "" {
		q = q.Where(fmt.Sprintf("%sname like ?", tbl), "%"+this.Name+"%")
	}
	if this.Sex > 0 {
		q = q.Where(fmt.Sprintf("%ssex = ?", tbl), this.Sex)
	}
	if this.Phone > 0 {
		q = q.Where(fmt.Sprintf("%sphone = ?", tbl), this.Phone)
	}
	if this.State > 0 {
		q = q.Where(fmt.Sprintf("%sstate = ?", tbl), this.State)
	}
	if this.Email != "" {
		q = q.Where(fmt.Sprintf("%semail like ?", tbl), "%"+this.Email+"%")
	}
	if this.Remark != "" {
		q = q.Where(fmt.Sprintf("%sremark like ?", tbl), "%"+this.Remark+"%")
	}
	return q
}
func (this *User) Find(scope ...string) (int, []User, error) {
	dl := []User{}

	q := MDB(EMDB_Permt).Table(&User{})
	q = this.condis(q, "")
	q = this.Sorte.condis(q, "", "id", this.Orders())
	q = this.Pager.condis(q, &CTimeField{ETF_Format, "created"})

	q = q.Where(util.Stringv(scope))
	total, err := q.FindAndCount(&dl)
	return int(total), dl, err
}

// ----- UserRole
func (this *UserRole) Insert(uId int64, rIds []int64) error {
	if len(rIds) == 0 {
		return nil
	}
	items := []UserRole{}
	for _, rId := range rIds {
		items = append(items, UserRole{UserId: uId, RoleId: rId})
	}
	for n := 0; ; n++ {
		end := (n + 1) * DEF_INSERT_BATCH_SIZE
		if end >= len(items) {
			end -= (end - len(items))
		}

		_, err := MDB(EMDB_Permt).Table(this).Insert(items[n*DEF_INSERT_BATCH_SIZE : end])
		if err != nil {
			return err
		}

		if end >= len(items) {
			break
		}
	}
	return nil
}
func (this *UserRole) Delete(uId, rId int64) (int64, error) {
	if uId == 0 && rId == 0 {
		return 0, errors.New("uId == 0 && rId == 0")
	}

	q := MDB(EMDB_Permt).Table(this)
	if uId != 0 {
		q = q.Where("user_id=?", uId)
	}
	if rId != 0 {
		q = q.Where("role_id=?", rId)
	}
	return q.Delete(&UserRole{})
}
func (this *UserRole) condis(q *xorm.Session, tbl string) *xorm.Session {
	util.Cast(tbl != "", func() { tbl += "." }, nil)

	if this.UserId != 0 {
		q.Where(fmt.Sprintf("%suser_id = ?", tbl), this.UserId)
	}
	if this.RoleId != 0 {
		q.Where(fmt.Sprintf("%srole_id = ?", tbl), this.RoleId)
	}
	return q
}
func (this *UserRole) FindIds() ([]int64, error) {
	ids := []int64{}

	q := MDB(EMDB_Permt).Table(this)

	util.Cast(this.UserId != 0, func() { q = q.Cols("role_id") }, nil)
	util.Cast(this.RoleId != 0, func() { q = q.Cols("user_id") }, nil)

	return ids, this.condis(q, "").Find(&ids)
}

// ----- UserGroup
func (this *UserGroup) Insert(uId int64, gIds []int64) error {
	if len(gIds) == 0 {
		return nil
	}

	items := []UserGroup{}
	for _, gId := range gIds {
		items = append(items, UserGroup{UserId: uId, GroupId: gId})
	}
	for n := 0; ; n++ {
		end := (n + 1) * DEF_INSERT_BATCH_SIZE
		if end >= len(items) {
			end -= (end - len(items))
		}

		_, err := MDB(EMDB_Permt).Table(this).Insert(items[n*DEF_INSERT_BATCH_SIZE : end])
		if err != nil {
			return err
		}

		if end >= len(items) {
			break
		}
	}
	return nil
}
func (this *UserGroup) Delete(uId, gId int64) (int64, error) {
	if uId == 0 && gId == 0 {
		return 0, errors.New("uId == 0 && gId == 0")
	}

	q := MDB(EMDB_Permt).Table(this)
	if uId != 0 {
		q = q.Where("user_id=?", uId)
	}
	if gId != 0 {
		q = q.Where("group_id=?", gId)
	}
	return q.Delete(&UserGroup{})
}
func (this *UserGroup) condis(q *xorm.Session, tbl string) *xorm.Session {
	util.Cast(tbl != "", func() { tbl += "." }, nil)

	if this.UserId != 0 {
		q.Where(fmt.Sprintf("%suser_id = ?", tbl), this.UserId)
	}
	if this.GroupId != 0 {
		q.Where(fmt.Sprintf("%sgroup_id = ?", tbl), this.GroupId)
	}
	return q
}
func (this *UserGroup) FindIds() ([]int64, error) {
	ids := []int64{}

	q := MDB(EMDB_Permt).Table(this)

	util.Cast(this.UserId != 0, func() { q = q.Cols("group_id") }, nil)
	util.Cast(this.GroupId != 0, func() { q = q.Cols("user_id") }, nil)

	return ids, this.condis(q, "").Find(&ids)
}

// ----- UserWithUserGroup
type UserWithUserGroup struct {
	User      `xorm:"extends"`
	UserGroup `xorm:"extends"`
	Sorte     SortFinder `json:"-" xorm:"-"`
	Pager     PageFinder `json:"-" xorm:"-"`
}

func (this *UserWithUserGroup) FindUsers(scope ...string) (int, []User, error) {
	dl := []User{}

	q := MDB(EMDB_Permt).Select("`user`.*")
	q = q.Join("INNER", "user_group", "user.id = user_group.user_id")

	q = this.User.condis(q, "user")
	q = this.UserGroup.condis(q, "user_group")
	q = this.Sorte.condis(q, "user", "id", nil)
	q = this.Pager.condis(q, &CTimeField{ETF_Format, "user.created"})

	q = q.Where(util.Stringv(scope))
	total, err := q.GroupBy("user.id").FindAndCount(&dl)
	return int(total), dl, err
}
